<!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="zh-Hans-CN" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="zh-Hans-CN" > <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
  <meta name="author" content="XenForo Ltd.">
  
  <link rel="shortcut icon" href="../img/favicon.ico">
  <title>管理 Schema - XenForo 2.0 开发人员说明文档</title>
	<link rel="stylesheet" href="../css/theme.css" type="text/css" />
	<link rel="stylesheet" href="../css/theme_extra.css" type="text/css" />
		<link href="../extra.css?d=2020-11-03%2013%3A06%3A33.008529%2B00%3A00" rel="stylesheet">

  
  <script>
    // Current page data
    var mkdocs_page_name = "\u7ba1\u7406 Schema";
    var mkdocs_page_input_path = "managing-the-schema.md";
    var mkdocs_page_url = null;
  </script>
  

  
  

  
  <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>

  <script src="../js/modernizr-2.8.3.min.js" defer></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
  <script>hljs.initHighlightingOnLoad();</script> 
  
</head>

<body class="wy-body-for-nav" role="document">

  <div class="wy-grid-for-nav">

    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
    <div class="wy-side-scroll">
      <div class="wy-side-nav-search">
        

        <div class="dropdown">
          <div class="lang_btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
            <i class="icon fa-globe"></i>
          </div>

          <div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
            <a class="dropdown-item" id="en" href="javascript:;">English</a>
            <a class="dropdown-item" id="zh_tw" href="javascript:;">繁体中文</a>
            <a class="dropdown-item" id="zh_cn" href="javascript:;">简体中文</a>
          </div>
        </div>
        <a href=".." class="icon icon-home"> XenForo 2.0<br>开发人员说明文档</a>
        <div role="search">
  <form id ="rtd-search-form" class="wy-form" action="../search.html" method="get">
    <input type="text" name="q" placeholder="搜寻文档" title="Type search term here" />
  </form>
</div>
        

      </div>

      <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
        <ul class="current">
                    <li class="toctree-l1"><a class="" href="..">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">入门须知</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../template-syntax/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">模板语法</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../rest-api/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">REST API</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../add-on-structure/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">附加组件架构</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../development-tools/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">开发工具</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../general-concepts/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">通用概念</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../routing-basics/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">路由基础知识</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../controller-basics/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">控制器基础知识</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../entities-finders-repositories/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">数据实体、查找器、保存库</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../criteria/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">准则</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1 current"><a class="current" href="./">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">管理 Schema</font>
    </font>
</a>

    <ul class="subnav">
    <li class="toctree-l2">
    	<a href="#_1">
    		<font style="vertical-align: inherit;">
                <font style="vertical-align: inherit;">数据库适配器</font>
            </font>
        </a>
    </li>
    <li class="toctree-l2">
    	<a href="#_2">
    		<font style="vertical-align: inherit;">
                <font style="vertical-align: inherit;">纲要管理</font>
            </font>
        </a>
    </li>
    </ul>

                    </li>
                    <li class="toctree-l1"><a class="" href="../lets-build-an-add-on/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">创建一个附加组件</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../designing-styles/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">设计样式</font>
    </font>
</a>

                    </li>
                    <li class="toctree-l1"><a class="" href="../scotchbox/">
    <font style="vertical-align: inherit;">
        <font style="vertical-align: inherit;">附录：Scotch Box</font>
    </font>
</a>

                    </li>
        </ul>
      </div>
    </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" role="navigation" aria-label="top navigation">
        <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
        <a href="..">XenForo 2.0<br>开发人员说明文档</a>
      </nav>

      
      <div class="wy-nav-content">
        <div class="rst-content">
          <div role="navigation" aria-label="breadcrumbs navigation">
  <ul class="wy-breadcrumbs">
    <li><a href="..">首页</a> &raquo;</li>
    
      
    
    <li>管理 Schema</li>
    <li class="wy-breadcrumbs-aside">
      
        <a href="https://github.com/EverSoar/xenforo2doc/edit/master/docs/managing-the-schema.md"
          class="icon icon-github"> 在 GitHub 上编辑</a>
      
    </li>
  </ul>
  
  <hr/>
</div>
          <div role="main">
            <div class="section">
              
	<h1 id="schema">管理 Schema<a class="headerlink" href="#schema" title="Permanent link">&para;</a></h1>
<p>我们已经看了一些可用于与数据交互的新方法。 当然，在一些特定情况下，可能需要直接与数据库进行交互。</p>
<h2 id="_1">数据库适配器<a class="headerlink" href="#_1" title="Permanent link">&para;</a></h2>
<p>XF2 中默认的数据库适配器是基于 MySQL 和 PHP 的 mysqli 扩展。 在任何 XF 类中都可以使用以下方法访问设置的数据库适配器：</p>
<pre><code class="language-php">$db = \XF::db();
</code></pre>
<p>适配器有许多可用的方法，这些方法将运行一个 SQL 查找，然后将结果格式化为一个数组。 例如，要访问一个用户记录：</p>
<pre><code class="language-php">$db = \XF::db();
$user = $db-&gt;fetchRow('SELECT * FROM xf_user WHERE user_id = ?', 1);
</code></pre>
<p><code>$user</code> 变量现在将包含一个数组，其中包含查找结果集中第一行的所有值。 要想从该查找中获得単一的值，例如用户名，可以运行以下操作：</p>
<pre><code class="language-php">$username = $user['username'];
</code></pre>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>直接编写并传递给数据库适配器的数据库查找并非自动 "安全"。 如果用户的输入没有经过清除，并且没有经过准备就传入查找，它们就会帯来 SQL 隐码攻击漏洞的风险。 正确的方法是使用准备好的语句，就象上面的例子一样。 在查找本身中使用 <code>?</code> 占位符来表示参数。 这些占位符经过适当的転义后，会被下一个参数中的值替换。 如果你需要使用的参数不止一个，那应该以数组的形式传递到 fetch 类型方法中。 如有必要，你可以直接使用 <code>$db-&gt;quote($value)</code> 对值进行転义或引用。</p>
<p>您可以 <a href="http://php.net/manual/en/mysqli.quickstart.prepared-statements.php">在这里</a> 找到更多关于准备好的语句信息。</p>
</div>
<p>也可以从一条记录中查找一个值。 例如：</p>
<pre><code class="language-php">$db = \XF::db();
$username = $db-&gt;fetchOne('SELECT username FROM xf_user WHERE user_id = ?', 1);
</code></pre>
<p>如果你有一个需要返回多条记录的查找，你可以使用 <code>fetchAll</code>：</p>
<pre><code class="language-php">$db = \XF::db();
$users = $db-&gt;fetchAll('SELECT * FROM xf_user LIMIT 10');
</code></pre>
<p>或者 <code>fetchAllKeyed</code>：</p>
<pre><code class="language-php">$db = \XF::db();
$users = $db-&gt;fetchAllKeyed('SELECT * FROM xf_user LIMIT 10', 'user_id');
</code></pre>
<p>这两种方法都将返回一个代表每个用户记录的数组。 <code>fetchAll</code> 和 <code>fetchAllKeyed</code> 方法之间的区别是，返回的数组的 key 值不同。 使用 <code>fetchAll</code> 方法时，数组将用连续的数字整数进行 key 锁定。 用 <code>fetchAllKeyed</code> 方法，数组将用第二个参数中命名的字段名进行 key 锁定。</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>如果你使用 <code>fetchAllKeyed</code>，请注意第二个参数是要对数组进行 key 锁定的字段，但 <strong>第三个</strong> 参数是你传递 param 值以匹配 <code>?</code> 占位符的地方。</p>
</div>
<p>还有一些其他获取类型的方法，包括 <code>fetchAllColumn</code>，用于从所有返回的 rows 中抓取一个特定 column 的值的数组：</p>
<pre><code class="language-php">$db = \XF::db();
$usernames = $db-&gt;fetchAllColumn('SELECT username FROM xf_user LIMIT 10');
</code></pre>
<p>上面的例子将返回一个从结果查找中找到的 10 个用户名的数组。</p>
<p>最后，你可能并不想要或不需要返回任何数据，在这种情况下，你可以只做一个普通查找：</p>
<pre><code class="language-php">$db = \XF::db();
$db-&gt;query('DELETE FROM xf_user WHERE user_id = ?', 1);
</code></pre>
<h2 id="_2">纲要管理<a class="headerlink" href="#_2" title="Permanent link">&para;</a></h2>
<p>XF2 包含了一种全新的管理数据库模式的方式，它采用物件导向的方式来运行某些表的操作。 让我们先看看传统的改变，使用数据库适配器，就象我们上面的那样。</p>
<pre><code class="language-php">$db = \XF::db();
$db-&gt;query(&quot;
    ALTER TABLE xf_some_existing_table
    ADD COLUMN new_column INT(10) UNSIGNED NOT NULL DEFAULT 0,
    MODIFY COLUMN some_existing_column varchar(250) NOT NULL DEFAULT ''
&quot;);
</code></pre>
<p>我们也来看看一个典型的创建资料表查找：</p>
<pre><code class="language-php">$db = \XF::db();
$sm = $db-&gt;getSchemaManager();

$defaultTableConfig = $sm-&gt;getTableConfigSql();

$db-&gt;query(&quot;
    CREATE TABLE xf_some_table (
        some_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
        some_name VARCHAR(50) NOT NULL,
        PRIMARY KEY (user_id)
    ) {$defaultTableConfig}
&quot;);
</code></pre>
<p>在 XF2 中，另一种和首选的方法是使用新的 <code>SchemaManager</code> 物件。 让我们来看看这两个由模式管理器运行的查找，首先是 alter：</p>
<pre><code class="language-php">$sm = \XF::db()-&gt;getSchemaManager();
$sm-&gt;alterTable('xf_some_existing_table', function(\XF\Db\Schema\Alter $table)
{
    $table-&gt;addColumn('new_column', 'int')-&gt;setDefault(0);
    $table-&gt;changeColumn('some_existing_column')-&gt;length(250);
});
</code></pre>
<p>还有资料表的创建：</p>
<pre><code class="language-php">$sm = \XF::db()-&gt;getSchemaManager();
$sm-&gt;createTable('xf_some_table', function(\XF\Db\Schema\Create $table)
{
    $table-&gt;addColumn('some_id', 'int')-&gt;autoIncrement();
    $table-&gt;addColumn('some_name', 'varchar', 50);
});
</code></pre>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>当您更改现有的 XenForo 资料表或创建自己的资料表时，<strong>必须</strong> 指定一个默认值，否则在查找资料表时将会遇到问题。</p>
</div>
<p>这两个例子生成的查找结果和上面更直接的例子完全一样。 不过你可能会注意到，有些东西是（故意）遗漏的。 例如，没有一个例子为 <code>int</code> 字段指定一个长度。 这只是因为省略了这一点，MySQL 会给它提供一个默认值，对于无符号整数来说是 10。说到这里，我们也没有指定 <code>some_id</code> column 是无符号的。 在 XF 内使用无符号整数是当前最常见的使用案例，所以会自动添加。 如果你真正需要支持负整数的能力，你可以用 <code>-&gt;unsigned(false)</code> 方法反过来。 另一个遗漏是没有为所有的东西定义 <code>NOT NULL</code>。 同样，这是自动应用的，但你可以用 <code>-&gt;nullable(true)</code> 来扭転这种情况。</p>
<p>从 alter 的例子中可能看不清楚，但是当改变现有的字段时，现有的字段定义会自动保留。 这意味着，你不必指定整个 column 的定义，包括所有没有实际改变的部分，你可以只指定你要改变的部分。</p>
<p>关于 Primary Key，还有一些其他的自动推断。 如果你愿意的话，你可以明确地定义 Primary Key（或任何其他类型的 Key ），但通常自动递增的字段通常会成为你的资料表的 Primary Key。 所以在创建资料表的例子中，<code>some_id</code> 字段被自动分配为该资料表的 Primary Key。</p>
<p>最后，对于创建资料表的方法，我们可以为指定的保存引擎自动添加正确的资料表设置（默认为 <code>InnoDB</code>，但可以很容易地改变为其他引擎类型）。</p>

            </div>
          </div>
          

<div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
  
  <a href="lets-build-an-add-on/" class="btn btn-neutral float-right" title="创建一个附加组件">下一页 <span class="icon icon-circle-arrow-right"></span></a>
  
  
  <a href="criteria/" class="btn btn-neutral" title="准则"><span class="icon icon-circle-arrow-left"></span> 上一页</a>
  
</div>


<footer>
  <div role="contentinfo">
    <!-- Copyright etc -->
    
    <p><a href="https://xenforo.com/" target="_blank">XenForo 开发者说明文档&trade; &copy; 2017-2018 XenForo Ltd.</a></p>
    
    <p>
      使用 <a href="http://www.mkdocs.org">MkDocs</a> 构建，该文档基于 <a href="https://readthedocs.org">Read the Docs</a> 提供的 <a href="https://github.com/snide/sphinx_rtd_theme">主题</a>，并由 <a href="https://xenforo.com">XenForo Ltd</a> 修改。
    </p>
  </div>
</footer>
      
        </div>
      </div>

    </section>

  </div>

  <div class="rst-versions" role="note" aria-label="versions">
    <span class="rst-current-version" data-toggle="rst-current-version">
      
          <a href="https://github.com/EverSoar/xenforo2doc/" class="fa fa-github" style="float: left; color: #fcfcfc"> GitHub</a>
      
      
        <span><a href="../criteria/" style="color: #fcfcfc;">&laquo; 上一页</a></span>
      
      
        <span style="margin-left: 15px"><a href="../lets-build-an-add-on/" style="color: #fcfcfc">下一页 &raquo;</a></span>
      
    </span>
</div>
    <script>var base_url = '..';</script>
    <script src="../js/theme.js" defer></script>
    <script src="../js/lang.js" defer></script>
      <script src="../search/main.js" defer></script>

</body>
</html>
